/*================================================================
*   Copyright (C) 2018 Guangzhou Firefly Ltd. All rights reserved.
*   
*   文件名称：dht11.c
*   创 建 者：luhuadong
*   创建日期：2018年11月29日
*   描    述：
*
================================================================*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "qapi/qapi.h"
#include "qapi/qapi_status.h"

#include "qapi/qapi_gpioint.h"
#include "qapi/qapi_tlmm.h"
#include "qapi/qapi_types.h"
#include "qapi/qapi_fs.h"
#include "qapi/qapi_timer.h"

#include "dht11.h"


#define FAIL    -1
#define SUCCESS  0
//#define GPIO_THREAD_EVENT_MASK                          (0x00000001)
#define DATA_LENGTH 5

enum modem_pin_value {
    MODEM_PIN_04 = 23,  // SoC_GPIO01, MCU_GPIO(SPI_CLK),   Arduino_D13
    MODEM_PIN_05 = 20,  // SoC_GPIO02, MCU_GPIO(SPI_MOSI),  Arduino_D11
    MODEM_PIN_06 = 21,  // SoC_GPIO03, MCU_GPIO(SPI_MISO),  Arduino_D12
    MODEM_PIN_07 = 22,  // SoC_GPIO04, MCU_GPIO(SPI_CS),    Arduino_D10
    MODEM_PIN_18 = 11,  // SoC_GPIO05, MCU_GPIO3(K2, KEY1), Arduino_D3
    MODEM_PIN_19 = 10,  // SoC_GPIO06, MCU_GPIO2(Sensor2),  Arduino_D2
    MODEM_PIN_22 =  9,  // SoC_GPIO07, MCU_GPIO(LOG_RX)
    MODEM_PIN_23 =  8,  // SoC_GPIO08, MCU_GPIO(LOG_TX)
    MODEM_PIN_26 = 15,  // SoC_GPIO09, MCU_GPIO4(Motor),    Arduino_D6
    MODEM_PIN_27 = 12,  // SoC_GPIO10, MCU_GPIO(UART3_TXD)
    MODEM_PIN_28 = 13,  // SoC_GPIO11, MCU_GPIO(UART3_RXD)
    MODEM_PIN_40 = 19,  // SoC_GPIO19, MCU_GPIO(I2C_SCL),   Arduino_SCL
    MODEM_PIN_41 = 18,  // SoC_GPIO20, MCU_GPIO(I2C_SDA),   Arduino_SDA
    MODEM_PIN_64 =  7   // SoC_GPIO21, MCU_GPIO8,           Arduino_D9
};

uint32_t dht11_pin = MODEM_PIN_19;
qapi_TLMM_Config_t dht11_config;
qapi_GPIO_ID_t     dht11GPIO;


static void dht11SetValue(uint8_t value);
static uint8_t dht11GetValue(void);
static uint8_t dht11GetByte(void);
static int8_t dht11Ready2Sample(void);
static qapi_Status_t dht11ConfigOutput(void);
static qapi_Status_t dht11ConfigInput(void);

void dht11Init(void)
{
    qapi_Status_t status;

	// Configure a GPIO for DHT11 sensor data pin
	
	dht11_config.pin   = dht11_pin;
	dht11_config.func  = 0; // Using the functionality tied to pin mux value 0
	dht11_config.dir   = QAPI_GPIO_OUTPUT_E;  // 初始状态为输出
	dht11_config.pull  = QAPI_GPIO_PULL_UP_E; // 总线空闲状态为高电平
	dht11_config.drive = QAPI_GPIO_2MA_E;

	// Get a unique ID
	status = qapi_TLMM_Get_Gpio_ID(&dht11_config, &dht11GPIO);

	if(status == QAPI_OK) {
		// Changes the DHT11 data pin configuration
		status = qapi_TLMM_Config_Gpio(dht11GPIO, &dht11_config);

		if(status != QAPI_OK) {
			iofPrintf("dht11Init ERROR: Configure GPIO failed, %d\n", status);
		}
	} else {
        iofPrintf("dht11Init ERROR: Get GPIO ID failed, %d\n", status);
    }

	// 总线空闲状态为高电平
    dht11SetValue(1);
}

void dht11Exit(void)
{
    qapi_Status_t status;

	// Release GPIO ID
    status = qapi_TLMM_Release_Gpio_ID(&dht11_config, dht11GPIO);
    if (status != QAPI_OK) {
        iofPrintf("qapi_TLMM_Release_Gpio_ID ERROR: %d\n", status);
    }
}

static qapi_Status_t dht11ConfigOutput(void)
{
	dht11_config.pin   = dht11_pin;
	dht11_config.func  = 0; 
	dht11_config.dir   = QAPI_GPIO_OUTPUT_E; 
	dht11_config.pull  = QAPI_GPIO_PULL_UP_E;
	dht11_config.drive = QAPI_GPIO_2MA_E;

	return qapi_TLMM_Config_Gpio(dht11GPIO, &dht11_config);
}

static qapi_Status_t dht11ConfigInput(void)
{
	dht11_config.pin   = dht11_pin;
	dht11_config.func  = 0; 
	dht11_config.dir   = QAPI_GPIO_INPUT_E;
	//QAPI_GPIO_KEEPER_E;QAPI_GPIO_PULL_UP_E;QAPI_GPIO_NO_PULL_E;QAPI_GPIO_PULL_DOWN_E
	dht11_config.pull  = QAPI_GPIO_PULL_UP_E;
	dht11_config.drive = QAPI_GPIO_2MA_E;

	return qapi_TLMM_Config_Gpio(dht11GPIO, &dht11_config);
}


static void dht11SetValue(uint8_t value)
{
    if (0 == value) {
        qapi_TLMM_Drive_Gpio(dht11GPIO, dht11_pin, QAPI_GPIO_LOW_VALUE_E);
    }
    else {
        qapi_TLMM_Drive_Gpio(dht11GPIO, dht11_pin, QAPI_GPIO_HIGH_VALUE_E);
    }
}

static uint8_t dht11GetValue(void)
{
    qapi_Status_t status;
	qapi_GPIO_Value_t value;

	status = qapi_TLMM_Read_Gpio(dht11GPIO, dht11_pin, &value);
	if(status != QAPI_OK) {
		iofPrintf("dht11GetValue ERROR: Can not read, %d\n", status);
	}
	return (QAPI_GPIO_LOW_VALUE_E == value ? 0 : 1);
}

static uint8_t dht11GetByte(void)
{
	uint8_t byte = 0;
	uint8_t i;

	for(i=0; i<8; i++) {
		byte  = byte << 1;
		// 等待50us的低电平时隙结束
		while(!dht11GetValue());

		// 高电平26-28us表示0，70us表示1
		qapi_Timer_Sleep(30, QAPI_TIMER_UNIT_USEC, true);
		if(dht11GetValue()) {
			byte |= 0x01;
			// 等待高电平结束
			while(dht11GetValue());
		}
	}
	return byte;
}

static int8_t dht11Ready2Sample(void)
{
	qapi_Status_t status;

	status = dht11ConfigOutput();
    if (status != QAPI_OK) {
        iofPrintf("dht11SendStartSignal ERROR: Change GPIO state failed, %d\n", status);
		return FAIL;
    }

	iofPrintf("\t@>_<@... 1\n");

	// 拉低，并且大于18ms，然后拉高
	dht11SetValue(0);
	qapi_Timer_Sleep(20, QAPI_TIMER_UNIT_MSEC, true);
	dht11SetValue(1);

	iofPrintf("\t@>_<@... 2\n");

	// 保持20-40us，切换成输入模式，等待DHT11响应信号
	qapi_Timer_Sleep(40, QAPI_TIMER_UNIT_USEC, true);
	status = dht11ConfigInput();
    if (status != QAPI_OK) {
        iofPrintf("dht11SendStartSignal ERROR: Change GPIO state failed, %d\n", status);
		return FAIL;
    }

	iofPrintf("\t@>_<@... 3\n");

	// 40us后检查DHT11的信号
	qapi_Timer_Sleep(40, QAPI_TIMER_UNIT_USEC, true);

	// 此时应该是低电平
	if(!dht11GetValue()) {

		// 等待80us的DHT11响应结束
		while(!dht11GetValue());
		// 40us后再检查是否为高电平
		qapi_Timer_Sleep(40, QAPI_TIMER_UNIT_USEC, true);
		// 等待80us的拉高信号结束，进入数据接收状态
		while(dht11GetValue());

		iofPrintf("\t@>_<@... 5\n");

		return SUCCESS;
	}

	iofPrintf("\t@>_<@... 4\n");

	return FAIL;
}

int8_t dht11GetData(dht11Data_t *data)
{
	uint8_t tmpData[DATA_LENGTH];
	uint8_t checkSum;
	uint8_t i;

	if(NULL == data) return FAIL;

	if(SUCCESS == dht11Ready2Sample()) {

		// 按字节读取数据
		for(i=0; i<DATA_LENGTH; i++) {
			tmpData[i] = dht11GetByte();
		}

		dht11ConfigOutput();
		dht11SetValue(1);

		iofPrintf("*@_@* dht11GetData: [0]=%d, [1]=%d, [2]=%d, [3]=%d\n");

		checkSum = tmpData[0] + tmpData[1] + tmpData[2] + tmpData[3];
		if(checkSum != tmpData[4]) {
			iofPrintf("dht11GetData ERROR: CheckSum incorrect.\n");
			return FAIL;
		}

		data->humi = tmpData[0] + tmpData[1] / 10.0;
		data->temp = tmpData[2] + tmpData[3] / 10.0;

		return SUCCESS;
	}
	else {
		dht11ConfigOutput();
		dht11SetValue(1);
		iofPrintf("dht11GetData ERROR: DHT11 not ready!\n");
		return FAIL;
	}
}


